Programming Assignment 2 Seam Carving 暴力实现
Robert Sedgewick教授在Coursera上开了一门算法课,这是图论中的一道编程作业题。
问题概述
图像由像素构成,可以看成是一张二维数组,其中的存储着Color,这样每个位置都有相应的颜色,就可以表示一张图片了。
这道题目的目的是resize图像,每次删除一行或一列颜色值最不明想的像素。
图像在二维数组中的表示 :
(255,101,51) (255,101,153) (255,101,255)
(255,153,51) (255,153,153) (255,153,255)
(255,203,51) (255,204,153) (255,205,255)
(255,255,51) (255,255,153) (255,255,255)
##解题思路
能量函数
如何界定某个像素是否明显,可以被删除呢?
是否明显是由周围的像素决定的,基于此有公式
pixel(x,y)的能量函数表示为:
Δx2(x, y) + Δy2(x, y)
其中,Δx2(x, y) = Rx(x, y)2 + Gx(x, y)2 + Bx(x, y)2
Rx、Gx、Bx分别为为pixel(x+1,y)与pixel(x-1,y)对应RGB的差值。
Δy2(x, y)同理。
最短路径
我想到的暴力求解的笨办法是,将图像的位置映射成唯一的整型索引,并算出其能量函数的值,加上起始终点两个虚拟位置(它门的能量值都为0)以此构造一张加权有向图。找出起始点到终点的最短路径。
顶点的权重
加权有向图的权重是指边的权重,而上面构造的图形的权重值是在顶点中表示的,这需要转化为边的权重。这很简单,只需要将将一条边的两个顶点的权重相加表示成边的权重即可。
##算法实现
能量函数
123456789101112131415161718192021222324252627282930313233343536373839
private Picture mPicture; private static final double BORDER_ENERGY = 255.0 * 255 * 3;/** * energy of pixel at column x and row y */public double energy(int x, int y) { if (x < 0 || x >= width() || y < 0 || y >= height()) throw new IndexOutOfBoundsException(); if (isBorder(x, y)) return BORDER_ENERGY; return energyFun(mPicture.get(x - 1, y), mPicture.get(x + 1, y)) + energyFun(mPicture.get(x, y - 1), mPicture.get(x, y + 1));} private double energyFun(Color color1, Color color2) { int r1 = color1.getRed(); int g1 = color1.getGreen(); int b1 = color1.getBlue(); int r2 = color2.getRed(); int g2 = color2.getGreen(); int b2 = color2.getBlue(); int delta = square(r1 - r2) + square(g1 - g2) + square(b1 - b2); return delta;}private int square(int i) { return i * i;}private boolean isBorder(int x, int y) { if (x == 0 || x == mPicture.width() - 1) return true; else if (y == 0 || y == mPicture.height() - 1) return true; else return false;}`
###找到垂直方向的最短路径
从图像中删除垂直最短路径(即最不明显的像素)
1234567891011121314151617181920212223
/** * remove vertical seam from current picture * * @param seam */ public void removeVerticalSeam(int[] seam) { if (height() <= 1) throw new java.lang.IllegalArgumentException(); Picture pic = new Picture(width() - 1, height()); for (int h = 0; h < pic.height(); h++) { for (int w = 0; w < seam[h]; w++) { pic.set(w, h, mPicture.get(w, h)); } for (int w = seam[h] + 1; w < width(); w++) { pic.set(w - 1, h, mPicture.get(w, h)); } } this.mPicture = pic; }`
##后记
提交了n次,虽然通过了正确性测试,但是timing的5个测试全部没有通过,看样子此算法还是太过复杂了。